package com.yu.transport.handler;

import com.yu.loader.ExtensionLoader;
import com.yu.serialize.Serializer;
import com.yu.transfer.RpcMessage;
import com.yu.transfer.RpcRequest;
import com.yu.transfer.RpcResponse;
import com.yu.transport.constants.NettyConstants;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;

/**
 * @PackageName: com.yu.transport.codec
 * @Description:
 * @Version: v1.0.0
 * @Author: yuweilin
 * @Date: 15:08
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ------------------------------------------------------------
 * 2021/1/27      yuweilin         v1.0.0               新建
 */
@Slf4j
public class RpcMessageDecoder extends LengthFieldBasedFrameDecoder {
    public RpcMessageDecoder() {
        this(NettyConstants.MAX_FRAME_LENGTH,NettyConstants.LENGTH_OFFSET,NettyConstants.LENGTH_FIELD_LENGTH,NettyConstants.CORRECTION_VALUE,0);
    }

    public RpcMessageDecoder(int maxFrameLength,int lengthFieldOffset, int lengthFieldLength,
                             int lengthAdjustment, int initialBytesToStrip){
        super(maxFrameLength,lengthFieldOffset,lengthFieldLength,lengthAdjustment,initialBytesToStrip);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        Object decode = super.decode(ctx, in);
        if (decode instanceof ByteBuf){
            ByteBuf frame = (ByteBuf) decode;
            if (frame.readableBytes() >= NettyConstants.HEAD_LENGTH){
                try {
                    return decodeFrame(frame);
                }catch (Exception e){
                    log.error("解码失败:[{}]",e.getMessage());
                    throw e;
                }finally {
                    in.release();
                }
            }
        }
        return in;
    }

    private Object decodeFrame(ByteBuf in){
        checkMagicNumber(in);
        byte version = in.readByte();
        //核对版本号
        checkVersion(version);
        int length = in.readInt();
        //把传过来的东西，封装成一个rpcMessage对象
        byte messageType = in.readByte();
        int requestId = in.readInt();
        RpcMessage message = RpcMessage.builder()
                .messageType(messageType)
                .requestId(requestId).build();
        if (messageType == NettyConstants.HEARTBEAT_TYPE){
            message.setData(NettyConstants.PING);
            return message;
        }
        int bodyLength = length-NettyConstants.HEAD_LENGTH;
        if (bodyLength>0){
            byte[] content = new byte[bodyLength];
            in.readBytes(content);
            log.info("序列化类型：[{}]","protostuff");
            Serializer serializer = ExtensionLoader.getExtensionLoader(Serializer.class).getExtension("protostuff");
            if (messageType==NettyConstants.REQUEST_TYPE){
                RpcRequest request = serializer.deserialize(content, RpcRequest.class);
                message.setData(request);
            }else {
                RpcResponse response = serializer.deserialize(content, RpcResponse.class);
                message.setData(response);
            }
        }
        return message;

    }

    private void checkVersion(byte version){
        if (version!=NettyConstants.VERSION){
            throw new RuntimeException("版本错误");
        }
    }

    private void checkMagicNumber(ByteBuf in){
        int len = NettyConstants.MAGIC_NUMBER.length;
        byte[] temp = new byte[len];
        in.readBytes(temp);
        for (int i=0;i<len;i++){
            if (temp[i]!=NettyConstants.MAGIC_NUMBER[i]){
                throw new RuntimeException("魔数错误："+ Arrays.toString(temp));
            }
        }
    }
}
